package com.group9.handinhand.controller;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.group9.handinhand.controller.form.OfferCreateForm;
import com.group9.handinhand.controller.form.OfferUpdateForm;
import com.group9.handinhand.controller.form.OfferViewForm;
import com.group9.handinhand.service.CommunityService;
import com.group9.handinhand.service.OfferService;
import com.group9.handinhand.service.TagService;
import com.group9.handinhand.service.so.ActivityEnums.ActivityType;
import com.group9.handinhand.service.so.CommunityMemberSO;
import com.group9.handinhand.service.so.CommunitySO;
import com.group9.handinhand.service.so.OfferPostSO;
import com.group9.handinhand.service.so.OfferResponseSO;
import com.group9.handinhand.service.so.OfferSO;
import com.group9.handinhand.service.so.TagSO;
import com.group9.handinhand.service.so.UserSO;
import com.group9.handinhand.service.so.UserTagSO;
/**
 * A class for Offer controller.
 * Extends AbstractBaseController
 */
@Controller
public class OfferController extends AbstractBaseController {
	
	@Autowired
	CommunityService communityService;
	
	@Autowired
	OfferService offerService;
	
	@Autowired
	private TagService tagService;
	
	private List<UserSO> moderatorsList;
	private UserSO creator;
	/**
	 * a controller for offer list
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/offers")
	public String offers(HttpServletRequest request, Model model){
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		
		List<OfferSO> respondedOfferList = offerService.getRespondedOffersByUser(user);
		List<OfferSO> moderatedOfferList = offerService.getModeratedOffersByUser(user);
		model.addAttribute("respondedOfferList", respondedOfferList);
		model.addAttribute("moderatedOfferList", moderatedOfferList);
		return "listOffers";
	}
	/**
	 * a controller for creating new offer
	 * @param communityId
	 * @param offerCreateForm
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/newOffer")
	public String newOffer(@PathVariable Long communityId, OfferCreateForm offerCreateForm, BindingResult errors, HttpServletRequest request, Model model){
		
		OfferSO so = new OfferSO();
		so.setCommunity(communityService.getCommunityById(communityId));
		offerCreateForm.setOffer(new OfferSO());
		
		return "newOffer";
	}
	/**
	 * a controller for saving an offer
	 * @param communityId
	 * @param offerCreateForm
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/saveOffer")
	public String saveOffer(@PathVariable Long communityId, OfferCreateForm offerCreateForm, BindingResult errors, HttpServletRequest request, Model model){
		
		validateNewOffer(offerCreateForm, errors);
		if(errors.hasErrors()){
			return newOffer(communityId, offerCreateForm, errors, request, model);
		}
		offerCreateForm.setEndDate();
		OfferSO offer = offerCreateForm.getOffer();
		
		offer = offerService.saveOffer(offer, getUser(), communityId);
		
		List<String> selectedTags = offerCreateForm.getSelectedTagsAsList();
		
		tagService.saveOfferTags(offer,selectedTags);
		
		return "redirect:/communities/" + communityId + "/offers/" + offer.getId();
	}
	/**
	 * A controller for listing offer of the community
	 * @param communityId
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/offers")
	public String listOffersOfCommunity(@PathVariable Long communityId, HttpServletRequest request, Model model){
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		
		CommunitySO community = communityService.getCommunityById(communityId);
		
		Set<OfferSO> offerList = community.getOffers();
		model.addAttribute("offerList", offerList);
		model.addAttribute("communityId", communityId);
		return "listOffersOfCommunity";
	}
	/**
	 * a controller for viewing an offer
	 * @param communityId
	 * @param offerId
	 * @param offerViewForm
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/offers/{offerId}")
	public String viewOffer(@PathVariable Long communityId, @PathVariable Long offerId, OfferViewForm offerViewForm, HttpServletRequest request, Model model){
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		CommunityMemberSO communityMemberSO = communityService.getCommunityMemberByCommunityIdAndUserId(communityId, user.getId());
		OfferSO offer = offerService.getOfferById(offerId);
		OfferSO moderatedOffer = offerService.getModeratedOfferByOfferIdAndUserId(offerId, user.getId());
		offerViewForm.setCommunityMember(communityMemberSO);
		offerViewForm.setModeratedOffer(moderatedOffer);
		offerViewForm.setOffer(offer);
		offerViewForm.setWallElementsFromOffer();
		
		ArrayList<OfferResponseSO> list = offerService.getRequestResponsesByUserIdAndOfferId(getUser().getId(), offerId);
		offerViewForm.setUserContributionFromList(list);
		
				// Find User Tags
				List<UserTagSO> userTags = tagService.getUserTagsByUser(user);
				offerViewForm.setUserTags(userTags);
				
				// Find Offers From User Tags 
				ArrayList<Object> offerList = new ArrayList<Object>();
				for(int i=0; i<userTags.size();i++){
					offerList.addAll(offerService.getOffersByTag(userTags.get(i)));
					}
				offerViewForm.setOfferList(offerList);
				
				
				List<OfferSO> offerListofModerated = offerService.getModeratedOffersByUser(user);
				model.addAttribute("offerListofModerated", offerListofModerated);
				
				offerListofModerated.add(offerService.getOfferById(offerId));
				
				
				// Exclude Moderated offers from above found
				for(int i=0; i<offerListofModerated.size();i++)
				{
				offerList.remove(offerListofModerated.get(i));
				}
				// Exclude Responded offers from above found
				List<OfferSO> offerListofResponded = offerService.getRespondedOffersByUser(user);
				model.addAttribute("offerListofResponded", offerListofResponded);
				
				for(int i=0; i<offerListofResponded.size();i++)
				{
				offerList.remove(offerListofResponded.get(i));
				}
				
				// Find Events of Community
//				ArrayList<Object> eventListofCommunity = new  ArrayList<Object>();
//				eventListofCommunity.addAll(communityService.getCommunityById(communityId).getEvents());
//				eventViewForm.setEventListofCommunity(eventListofCommunity);
//				
//				// Find Events of Community according User Tags
//				ArrayList<Object> eventListofRecommendation = new  ArrayList<Object>();
//				for(int i=0;i<eventListofCommunity.size();i++)
//				{
//					if(eventList.contains(eventListofCommunity.get(i)))
//					{
//						eventListofRecommendation.add(eventListofCommunity.get(i));
//					}
//				}
//				eventViewForm.setEventListofRecommendation(eventListofRecommendation);	

				
//				// Exclude Already Member Events from above found
//				for(int i=0; i<eventListofUser.size();i++)
//				{
//				eventListofRecommendation.remove(eventListofUser.get(i));
//				}
		
		
		
		
		
		return "viewOffer";
	}

	private void validateNewOffer(OfferCreateForm offerCreateForm, BindingResult errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "offer.name", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingDay", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingHour", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "offer.description", "required.field");
		OfferSO offer = offerCreateForm.getOffer();
		if(offer.getActivityType() == ActivityType.GOODS) {
			offer.setService(null);
		}
		else if(offer.getActivityType() == ActivityType.SERVICES) {
			offer.setGoods(null);
		}
		else {
			offer.setGoods(null);
			offer.setService(null);
		}
		
	}
	private void validateEditedOffer(OfferUpdateForm offerUpdateForm, BindingResult errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "offer.name", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingDay", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingHour", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "offer.description", "required.field");
		OfferSO offer = offerUpdateForm.getOffer();
		if(offer.getActivityType() == ActivityType.GOODS) {
			offer.setService(null);
		}
		else if(offer.getActivityType() == ActivityType.SERVICES) {
			offer.setGoods(null);
		}
		else {
			offer.setGoods(null);
			offer.setService(null);
		}
		
	}
	/**
	 * a method for validating edited offer
	 * @param offerUpdateForm
	 */
	private void validateEditedOffer(OfferUpdateForm offerUpdateForm) {
		OfferSO offer = offerUpdateForm.getOffer();
		if(offer.getActivityType() == ActivityType.GOODS) {
			offer.setService(null);
		}
		else if(offer.getActivityType() == ActivityType.SERVICES) {
			offer.setGoods(null);
		}
		else {
			offer.setGoods(null);
			offer.setService(null);
		}
		
	}
	/**
	 * a controller for posting on offer
	 * @param communityId
	 * @param offerId
	 * @param offerViewForm
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/offers/{offerId}/post")
	public String post(@PathVariable Long communityId, @PathVariable Long offerId, OfferViewForm offerViewForm, HttpServletRequest request, Model model){
		
		String post = offerViewForm.getPost();
		
		System.out.println(post);
		
//		CommunitySO community = communityService.getCommunityById(communityId);
		UserSO user = getUser();
		
		OfferPostSO offerPost;
//		if(community != null && user != null)	
			offerPost = offerService.saveOfferPost(offerId, user.getId(), post);
		
		return "redirect:/communities/{communityId}/offers/" + offerId;
	}
	/**
	 * a controller for responding to an offer
	 * @param communityId
	 * @param offerId
	 * @param offerViewForm
	 * @param req
	 * @param model
	 * @param errors
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/offers/{offerId}/respond")
	public String respond(@PathVariable Long communityId, @PathVariable Long offerId, OfferViewForm offerViewForm, HttpServletRequest req, Model model, BindingResult errors){
		
		OfferSO offer = offerService.getOfferById(offerId);
		offerViewForm.setOffer(offer);
		
		validateGoodsOrService(offerViewForm, errors);
		if(errors.hasErrors()){
			return viewOffer(communityId, offerId, offerViewForm, req, model);
		}
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		
		if(offerViewForm.getOffer().getActivityType() == ActivityType.SERVICES){
			offerService.saveOfferResponse(offer, user.getId(), offerViewForm.getServicesAmount());
		}
		else if(offerViewForm.getOffer().getActivityType() == ActivityType.GOODS){
			offerService.saveOfferResponse(offer, user.getId(), offerViewForm.getGoodsAmount());
		}

		return "redirect:/communities/{communityId}/offers/" + offerId;
	}
	
	@RequestMapping(value = "/communities/{communityId}/offers/{offerId}/editOffer")
	public String editOffer(@PathVariable Long communityId, @PathVariable Long offerId, OfferUpdateForm offerUpdateForm,  BindingResult errors, HttpServletRequest request, Model model){
		
		OfferSO offer = offerService.getOfferById(offerId);
		
		if(offer != null){
			offerUpdateForm.setOffer(offer);
			List<TagSO> selectedTags = tagService.getTagsByRelatedOfferId(offerId);
			moderatorsList = offerService.getModeratorsByOfferId(offerId);
			creator = offer.getCreator();
			offerUpdateForm.setSelectedTagsFromList(selectedTags);
			DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
			String endingDate = df.format(offer.getExpirationDate());    
			offerUpdateForm.setEndingDay(endingDate.substring(0,10));
			offerUpdateForm.setEndingHour(endingDate.substring(10));

		}

		return "updateOffer";
	}
	/**
	 * a controller for updating an offer
	 * @param communityId
	 * @param offerId
	 * @param offerUpdateForm
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/offers/{offerId}/updateOffer", method = RequestMethod.POST)
	public String updateOffer(@PathVariable Long communityId, @PathVariable Long offerId, OfferUpdateForm offerUpdateForm, BindingResult errors, HttpServletRequest request, Model model){
		
		validateEditedOffer(offerUpdateForm, errors);
		if(errors.hasErrors()){
			return editOffer(communityId, offerId, offerUpdateForm, errors, request, model);
		}
		offerUpdateForm.setEndDate();
		OfferSO offer = offerUpdateForm.getOffer();
		
		for(UserSO so : moderatorsList)
		{
			offer.getModerators().add(so);
		}
		
		System.out.println("----------------------------------  " + offer.getId());;
		
		offer.setId(offerId);
		offer.setCreator(creator);
		offer.setCommunity(communityService.getCommunityById(communityId));
		offerService.updateOffer(offer);
		
		List<String> selectedTags = offerUpdateForm.getSelectedTagsAsList();
		
		tagService.saveOfferTags(offer,selectedTags);	
				
		return "redirect:/communities/" + communityId + "/offers/" + offerId + "/editOffer";
	}
	/**
	 * a method for validating good or service
	 * @param offerViewForm
	 * @param errors
	 */
	private void validateGoodsOrService(OfferViewForm offerViewForm,  BindingResult errors) {
		if(offerViewForm.getOffer().getActivityType() == ActivityType.SERVICES){
			ValidationUtils.rejectIfEmptyOrWhitespace(errors, "servicesAmount", "Required field");
			if(offerViewForm.getOffer().getService().getRequiredNumber() - 
					offerViewForm.getOffer().getService().getRespondedAmount() < offerViewForm.getServicesAmount())
				errors.rejectValue("servicesAmount", "Amount cannot be greater than the required amount");
		}
		else if(offerViewForm.getOffer().getActivityType() == ActivityType.GOODS){
			ValidationUtils.rejectIfEmptyOrWhitespace(errors, "goodsAmount", "Required field");
			if(offerViewForm.getOffer().getGoods().getTargetAmount() - 
					offerViewForm.getOffer().getGoods().getRespondedAmount()< offerViewForm.getGoodsAmount())
				errors.rejectValue("goodsAmount", "Amount cannot be greater than the required amount");
		}
		
	}
	
}
